package com.snail.ron.design.singleton;

/**
 * @author xueguoping
 * @desc: TODO 双重检测DCL
 * 双重检测机制（双重检查加锁），比较常见的一种写法。在第一次使用的时间才进行初始化，达到了懒加载的效果；
 * 在进行初始化的时候会进行同步（加锁），因此没有线程安全问题；并且只有第一次进行初始化才进行同步，因此不会有效率方面的问题
 * 《Java Concurrency in Practice》作者Brian Goetz 在书中提到关于DCL的观点：促使DCL模式出现的驱动力（无竞争同步的执行速度很慢，以及JVM启动时很慢）已经不存在，因而它不是一种高效的优化措施。
 * 延迟初始化占位类模式（静态内部类）能带来同样的优势，并且更容易理解。
 * 总结：线程安全、懒加载、效率高
 * 是否推荐：可以使用。
 *
 * 为什么不能去掉volatile
 *      singletonThree = new SingletonThree(); 对象初始化，其实相当于三条命令
 *          1、memory = allocate() 分配对象内存空间
 *          2、ctorInstance(memory()) 初始化对象
 *          3、singletonThree = memory() 设置singletonThree指向刚才被分配的内存地址
 *      如果没有volatitle,CPU内部会在保证 不影响最终结果（只针对单线程）的前提下对指令进行 重排序（主要目的是未来提高效率）,如果上面3条指令被重排成以下顺序：
 *          1、memory = allocate() 分配对象内存空间
 *          3、singletonThree = memory() 设置singletonThree指向刚才被分配的内存地址
 *          2、ctorInstance(memory()) 初始化对象
 *      此时如果线程A执行完1，3，singletonThree对象还未完成初始化，但是此时已经不再指向null。
 *      此时线程B抢占到CPU资源，执行if(singletonThree == null)结果为false,从而返回一个还未初始化完成的singletonThree对象，从而出现问题
 *
 * @date 2022/4/1110:35
 */
public class SingletonThree {
   //私有构造
    private SingletonThree(){}

    //声明(放置对象初始化出现指令重排序)
    private static volatile SingletonThree singletonThree;

    //public双重检测
    public static SingletonThree getInstance(){
        if(singletonThree == null){
            synchronized (SingletonThree.class){
                if(singletonThree == null){
                    singletonThree = new SingletonThree();
                }
            }
        }
        return singletonThree;
    }
}
